package com.zlkj.pro.modular.app.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.file.api.constants.FileConstants;
import cn.stylefeng.roses.kernel.rule.constants.RuleConstants;
import cn.stylefeng.roses.kernel.sms.api.constants.SmsConstants;
import cn.stylefeng.roses.kernel.sms.api.exception.SmsException;
import cn.stylefeng.roses.kernel.sms.modular.entity.SysSms;
import cn.stylefeng.roses.kernel.sms.modular.enums.SmsSendSourceEnum;
import cn.stylefeng.roses.kernel.sms.modular.enums.SmsSendStatusEnum;
import cn.stylefeng.roses.kernel.sms.modular.param.SysSmsSendParam;
import cn.stylefeng.roses.kernel.sms.modular.param.SysSmsVerifyParam;
import cn.stylefeng.roses.kernel.sms.modular.service.SysSmsInfoService;
import cn.stylefeng.roses.kernel.system.api.UserServiceApi;
import cn.stylefeng.roses.kernel.system.api.exception.SystemModularException;
import cn.stylefeng.roses.kernel.system.api.exception.enums.user.SysUserExceptionEnum;
import cn.stylefeng.roses.kernel.system.api.pojo.user.SysUserDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.user.UserLoginInfoDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.user.request.SysUserRequest;
import cn.stylefeng.roses.kernel.system.modular.user.entity.SysUser;
import cn.stylefeng.roses.kernel.system.modular.user.factory.SysUserCreateFactory;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserOrgService;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserRoleService;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlkj.pro.core.consts.ProjectConstants;
import com.zlkj.pro.core.exception.BusinessException;
import com.zlkj.pro.core.sms.HuaweiSmsSender;
import com.zlkj.pro.core.util.ConvertUtil;
import com.zlkj.pro.modular.admin.entity.User;
import com.zlkj.pro.modular.admin.mapper.UserMapper;
import com.zlkj.pro.modular.admin.model.dto.SmsDTO;
import com.zlkj.pro.modular.admin.model.dto.UserDTO;
import com.zlkj.pro.modular.admin.model.vo.UserVO;
import com.zlkj.pro.modular.admin.service.ConfigService;
import com.zlkj.pro.modular.admin.service.UsersService;
import com.zlkj.pro.modular.app.mapper.AppUserMapper;
import com.zlkj.pro.modular.app.service.AppUsersService;
import com.zlkj.pro.modular.business.entity.AgentEntity;
import com.zlkj.pro.modular.business.model.dto.AreaDTO;
import com.zlkj.pro.modular.business.model.vo.AgentVO;
import com.zlkj.pro.modular.business.model.vo.AreaVO;
import com.zlkj.pro.modular.business.service.AgentService;
import com.zlkj.pro.modular.business.service.AreaService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.zlkj.pro.core.exception.enums.BusinessExceptionEnum.BUSINESS_EXCEPTION;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class AppUsersServiceImpl extends ServiceImpl<UserMapper, User> implements AppUsersService {


    @Autowired
    UsersService usersService;

    @Autowired
    private AppUserMapper appUserMapper;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private UserServiceApi userServiceApi;

    @Resource
    private PasswordStoredEncryptApi passwordStoredEncryptApi;

    @Resource
    private CacheOperatorApi<SysUserDTO> sysUserCacheOperatorApi;

    @Autowired
    private Environment env;

    @Resource
    ConfigService configService;

    @Resource
    private SysUserOrgService sysUserOrgService;

    @Resource
    private SysSmsInfoService sysSmsInfoService;

    @Resource
    private AreaService areaService;

    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private WxMpService wxMpService;

    @Autowired
    private AgentService agentService;
    @Autowired
    private UserMapper userMapper;


    @Override
    @Transactional(rollbackFor = {Exception.class}, noRollbackFor = {BusinessException.class})
    public UserVO login(UserDTO dto, Boolean validatePassword) {

        UserVO vo = new UserVO();


        // 1.必填校验
        if (validatePassword) {
            if (StringUtils.isEmpty(dto.getAccount())) {
                throw new BusinessException(BUSINESS_EXCEPTION, "账号不能为空");
            } else if (StringUtils.isEmpty(dto.getPassword())) {
                throw new BusinessException(BUSINESS_EXCEPTION, "密码不能为空");
            }
        }

        // 2. 获取用户和账号信息
        SysUser sysUser = sysUserService.getUserByAccount(dto.getAccount());
        Long userId = sysUser.getUserId();
        vo.setUserId(userId);

        // 3. 获取用户密码的加密值和用户的状态
        UserLoginInfoDTO userValidateInfo = userServiceApi.getUserLoginInfo(dto.getAccount());
        if (userValidateInfo.getUserStatus() != 1) {
            throw new BusinessException(BUSINESS_EXCEPTION, "账号已经被冻结");
        }
        // 4. 校验用户密码是否正确
        if (validatePassword) {
            Boolean checkResult = passwordStoredEncryptApi.checkPassword(dto.getPassword(), userValidateInfo.getUserPasswordHexed());
            if (!checkResult) {
                throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
            }
        }

        //绑定openid、unionid
        this.bindWxMaOpenId(sysUser.getUserId(), dto.getCode());

        // 5. 获取用户角色信息
        List<Long> roleIds = sysUserRoleService.findRoleIdsByUserId(userId);
        if (ObjectUtil.isEmpty(roleIds)) {
            throw new SystemModularException(AuthExceptionEnum.ROLE_IS_EMPTY);
        }
        if (!roleIds.contains(ProjectConstants.ROLE_ID_JL) && !roleIds.contains(ProjectConstants.ROLE_ID_YG)
                && !roleIds.contains(ProjectConstants.ROLE_ID_AGENT_MANAGER)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "登记成功，当前账号不可登录小程序。");
        }

        // 6.代理商禁用后 所有账号禁止登录
        User user = userMapper.selectById(userId);
        if (user != null && user.getAgentId() != null) {
            AgentEntity agent = agentService.getById(user.getAgentId());
            if (agent != null && agent.getStatusFlag().equals(2)) {
                throw new BusinessException(BUSINESS_EXCEPTION, "您所在代理商已禁用");
            }
        }

        return vo;
    }

    @Override
    public UserVO loginWithSmsCode(UserDTO dto) {

        // 参数校验
        if (StringUtils.isEmpty(dto.getPhone())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号不能为空");
        } else if (StringUtils.isEmpty(dto.getSmsCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "短信验证码不能为空");
        }

        try {
            // 验证验证码是否正确
            SysSmsVerifyParam param = new SysSmsVerifyParam();
            param.setPhone(dto.getPhone());
            param.setCode(dto.getSmsCode());
            param.setTemplateCode(HuaweiSmsSender.LOGIN_TEMPLATE_ID);
            param.setSmsSendSourceEnum(SmsSendSourceEnum.APP);
            sysSmsInfoService.validateSmsInfo(param);
        } catch (SmsException smsException) {
            if (smsException.getErrorCode().equals(RuleConstants.USER_OPERATION_ERROR_TYPE_CODE + SmsConstants.SMS_EXCEPTION_STEP_CODE + "08")) {
                throw new BusinessException(BUSINESS_EXCEPTION, "验证码已过期，请刷新获取新的验证码");
            } else {
                throw new BusinessException(BUSINESS_EXCEPTION, "验证码错误，请核对后重新输入");
            }
        }

        // 根据手机号查询用户账号
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(User::getPhone, dto.getPhone());
        queryWrapper.eq(User::getDelFlag, "N");
        List<User> userList = super.list(queryWrapper);
        if (CollectionUtils.isEmpty(userList)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号用户不存在！");
        }
        if (userList.size() > 1) {
            throw new BusinessException(BUSINESS_EXCEPTION, "当前手机号绑定多个用户！");
        }

        // 走账号登录的逻辑
        UserDTO userDto = new UserDTO();
        userDto.setAccount(userList.get(0).getAccount());
        // 透传获取openId的code
        userDto.setCode(dto.getCode());
        return this.login(userDto, false);
    }

    @Override
    public void getSmsCode(SmsDTO dto) {
        if (StringUtils.isEmpty(dto.getPhone())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号不能为空");
        }
        if (dto.getType() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "type不能为空");
        }
        // 发送短信
        // 生成六位随机验证码
        String code = RandomUtil.randomNumbers(6);
        String templateId = null;
        try {
            if (dto.getType() == 1) {
                templateId = HuaweiSmsSender.LOGIN_TEMPLATE_ID;
                // 登录
            } else {
                // 修改密码
                templateId = HuaweiSmsSender.PASSWORD_TEMPLATE_ID;
            }
            HuaweiSmsSender.sendMsg(templateId, dto.getPhone(), code);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 保存验证码
        SysSmsSendParam param = new SysSmsSendParam();
        param.setPhone(dto.getPhone());
        param.setSmsSendSourceEnum(SmsSendSourceEnum.APP);
        param.setTemplateCode(templateId);
        Long smsId = sysSmsInfoService.saveSmsInfo(param, code);

        SysSms sysSms = new SysSms();
        sysSms.setSmsId(smsId);
        sysSms.setStatusFlag(SmsSendStatusEnum.SUCCESS.getCode());
        sysSmsInfoService.updateById(sysSms);
    }

    @Override
    public void forgotPassword(UserDTO dto) {

        // 参数校验
        if (StringUtils.isEmpty(dto.getPhone())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号不能为空");
        } else if (StringUtils.isEmpty(dto.getSmsCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "短信验证码不能为空");
        } else if (StringUtils.isEmpty(dto.getPassword())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "新密码不能为空");
        }

        // 验证验证码是否正确
        try {
            SysSmsVerifyParam param = new SysSmsVerifyParam();
            param.setPhone(dto.getPhone());
            param.setCode(dto.getSmsCode());
            param.setTemplateCode(HuaweiSmsSender.PASSWORD_TEMPLATE_ID);
            param.setSmsSendSourceEnum(SmsSendSourceEnum.APP);
            sysSmsInfoService.validateSmsInfo(param);
        } catch (SmsException smsException) {
            if (smsException.getErrorCode().equals(RuleConstants.USER_OPERATION_ERROR_TYPE_CODE + SmsConstants.SMS_EXCEPTION_STEP_CODE + "08")) {
                throw new BusinessException(BUSINESS_EXCEPTION, "验证码已过期，请刷新获取新的验证码");
            } else {
                throw new BusinessException(BUSINESS_EXCEPTION, "验证码错误，请核对后重新输入");
            }
        }

        // 根据手机号查询用户账号
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(User::getPhone, dto.getPhone());
        queryWrapper.eq(User::getDelFlag, "N");
        List<User> userList = super.list(queryWrapper);
        if (CollectionUtils.isEmpty(userList)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号用户不存在！");
        }
        if (userList.size() > 1) {
            throw new BusinessException(BUSINESS_EXCEPTION, "当前手机号绑定多个用户！");
        }

        //修改密码
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userList.get(0).getUserId());
        sysUser.setPassword(passwordStoredEncryptApi.encrypt(dto.getPassword()));
        sysUserService.updateById(sysUser);

        // 清除缓存中的用户信息
        sysUserCacheOperatorApi.remove(String.valueOf(dto.getUserId()));
    }

    @Override
    public void changePassword(UserDTO dto) {

        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        } else if (StringUtils.isEmpty(dto.getOldPassword())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "原密码不能为空");
        } else if (StringUtils.isEmpty(dto.getPassword())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "新密码不能为空");
        }


        SysUser sysUser = sysUserService.getById(dto.getUserId());

        // 原密码错误
        if (!passwordStoredEncryptApi.checkPassword(dto.getOldPassword(), sysUser.getPassword())) {
            throw new SystemModularException(SysUserExceptionEnum.USER_PWD_ERROR);
        }

        SysUser updateSysUser = new SysUser();
        updateSysUser.setUserId(sysUser.getUserId());
        updateSysUser.setPassword(passwordStoredEncryptApi.encrypt(dto.getPassword()));
        sysUserService.updateById(updateSysUser);

        // 清除缓存中的用户信息
        sysUserCacheOperatorApi.remove(String.valueOf(dto.getUserId()));
    }

    @Override
    public void changePhone(UserDTO dto) {

        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        } else if (StringUtils.isEmpty(dto.getPhone())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号不能为空");
        }


        // 根据手机号查询用户账号
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.ne(User::getUserId, dto.getUserId());
        queryWrapper.eq(User::getPhone, dto.getPhone());
        queryWrapper.eq(User::getDelFlag, "N");
        List<User> userList = super.list(queryWrapper);
        if (!userList.isEmpty()) {
            throw new BusinessException(BUSINESS_EXCEPTION, "当前手机号已绑定其他账号！");
        }

        SysUser updateSysUser = new SysUser();
        updateSysUser.setUserId(dto.getUserId());
        updateSysUser.setPhone(dto.getPhone());
        sysUserService.updateById(updateSysUser);

    }

    @Override
    public void changeName(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        } else if (StringUtils.isEmpty(dto.getRealName())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "姓名不能为空");
        }

        SysUser updateSysUser = new SysUser();
        updateSysUser.setUserId(dto.getUserId());
        updateSysUser.setRealName(dto.getRealName());
        sysUserService.updateById(updateSysUser);
    }

    @Override
    public void changeAvatar(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        } else if (dto.getAvatar() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "avatar不能为空");
        }
        SysUser updateSysUser = new SysUser();
        updateSysUser.setUserId(dto.getUserId());
        updateSysUser.setAvatar(dto.getAvatar());
        sysUserService.updateById(updateSysUser);
    }

    @Override
    public List<UserVO> getAgentUserListByAgentId(UserDTO dto) {

        // 角色赋值
        dto.setUserId(LoginContext.me().getLoginUser().getUserId());
        extracted(dto);
        List<UserVO> userList = appUserMapper.getAgentUserListByAgentId(dto);
        if (CollectionUtils.isNotEmpty(userList)) {
            userList.forEach(vo -> {
                if (vo.getAvatar() != null) {
                    vo.setAvatarUrl(env.getProperty("file-path") + vo.getAvatar());
                }
                if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
                    vo.setRoleId(1L);
                } else if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
                    vo.setRoleId(2L);
                }
            });
            userList.removeIf(vo -> vo.getRoleId() != null
                    && !vo.getRoleId().equals(1L)
                    && !vo.getRoleId().equals(2L));
        }
        return userList;
    }

    private void extracted(UserDTO dto) {
        SysUserRequest sysUserRequest = new SysUserRequest();
        sysUserRequest.setUserId(dto.getUserId());
        SysUserDTO currentUser = sysUserService.detail(sysUserRequest);
        Long roleId = currentUser.getGrantRoleIdList().get(0);
        if (ProjectConstants.ROLE_ID_BMSH_MANAGER.equals(roleId)) {
            dto.setRoleId(1L);
        } else if (ProjectConstants.ROLE_ID_BMSH_YG.equals(roleId)) {
            dto.setRoleId(2L);
        } else if (ProjectConstants.ROLE_ID_AGENT_MANAGER.equals(roleId)) {
            dto.setRoleId(3L);
        } else if (ProjectConstants.ROLE_ID_JL.equals(roleId)) {
            dto.setRoleId(4L);
        } else if (ProjectConstants.ROLE_ID_YG.equals(roleId)) {
            dto.setRoleId(5L);
        }
    }

    @Override
    public UserVO getUserInfo(Long userId) {
        UserVO vo = appUserMapper.findDetail(userId);
        vo.setAvatarUrl(env.getProperty("file-path") + vo.getAvatar());
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_AGENT_MANAGER)) {
            vo.setRoleId(0L);
        }
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
            vo.setRoleId(1L);
        }
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
            vo.setRoleId(2L);
        }
        return vo;
    }

    @Override
    public AgentVO getAgentInfo(Long userId) {

        // 查询个人代理商信息
        AgentVO vo = appUserMapper.getAgentInfo(userId);

        // 获取共享区域
        AreaDTO dto = new AreaDTO();
        dto.setSharing(1);
        List<AreaVO> areas = areaService.findList(dto);
        // 从areas中收集name
        List<String> sharingAreas = areas.stream().map(AreaVO::getName).collect(Collectors.toList());
        // sharingAreas 转逗号分割字符串
        vo.setShareArea(StringUtils.join(sharingAreas, ","));
        vo.setLogoUrl(env.getProperty("file-path") + vo.getLogoFileId());
        return vo;
    }

    @Override
    public List<UserVO> getAgentUserList(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        }

        // 查询个人代理商信息
        AgentVO agentVO = appUserMapper.getAgentInfo(dto.getUserId());
        dto.setAgentId(agentVO.getId());


        if (ObjectUtil.isNotNull(dto.getRealName())) dto.setManageFlag(1);
        else dto.setManageFlag(0);

        // 角色赋值
        extracted(dto);
        List<UserVO> userList = appUserMapper.getAgentUserList(dto);
        if (CollectionUtils.isNotEmpty(userList)) {
            userList.forEach(vo -> {
                if (vo.getAvatar() != null) {
                    vo.setAvatarUrl(env.getProperty("file-path") + vo.getAvatar());
                }
                if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_AGENT_MANAGER)) {
                    vo.setRoleId(0L);
                }else if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
                    vo.setRoleId(1L);
                } else if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
                    vo.setRoleId(2L);
                }
            });

            userList.removeIf(vo -> vo.getRoleId() != null
                    && (!vo.getRoleId().equals(0L) && 0 == dto.getManageFlag())
                    && !vo.getRoleId().equals(1L)
                    && !vo.getRoleId().equals(2L));

        }
        return userList;
    }

    @Override
    public List<UserVO> findManagers(Long userId) {

        // 参数校验
        if (userId == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        }

        // 查询个人代理商信息
        AgentVO agentVO = appUserMapper.getAgentInfo(userId);
        UserDTO dto = new UserDTO();
        dto.setAgentId(agentVO.getId());
        dto.setRoleId(ProjectConstants.ROLE_ID_JL);
        return appUserMapper.findManagers(dto);
    }

    @Override
    public boolean add(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "当前用户userId不能为空");
        }

        // 超管权限执行操作
        //LoginContext.me().getLoginUser().setSuperAdmin(true);
        /*LoginUser loginUser = new LoginUser();
        loginUser.setUserId(dto.getUserId());
        User currentUser = super.getById(dto.getUserId());
        loginUser.setAccount(currentUser.getAccount());
        loginUser.setSuperAdmin(false);
        LoginUserHolder.set(loginUser);*/

        // 参数校验
        if (StringUtils.isBlank(dto.getPassword()) || dto.getPassword().length() < 8 || dto.getPassword().length() > 16) {
            throw new BusinessException(BUSINESS_EXCEPTION, "密码格式为8-16位数字、字母或符号组合");
        }
        if (StringUtils.isBlank(dto.getRealName())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "姓名不能为空");
        }
        if (StringUtils.isBlank(dto.getPhone())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号不能为空");
        }
        if (StringUtils.isBlank(dto.getAccount())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "账号不能为空");
        }
        if (dto.getRoleId() == null || (dto.getRoleId() != 1L && dto.getRoleId() != 2L)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "roleId不合法");
        } else if (dto.getRoleId() == 2L && dto.getLeaderId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "员工必须选择直属上级");
        }

        // 根据手机号查询用户账号
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(User::getPhone, dto.getPhone());
        queryWrapper.eq(User::getDelFlag, "N");
        List<User> userList = super.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(userList)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "手机号已经注册！");
        }

        LambdaQueryWrapper<User> queryWrapper2 = Wrappers.lambdaQuery();
        queryWrapper2.eq(User::getAccount, dto.getAccount());
        queryWrapper2.eq(User::getDelFlag, "N");
        List<User> userList2 = super.list(queryWrapper2);
        if (CollectionUtils.isNotEmpty(userList2)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "账号已经注册！");
        }

        // 创建账号
        SysUserRequest sysUserRequest = ConvertUtil.turn(dto, SysUserRequest.class);
        sysUserRequest.setUserId(IdUtil.getSnowflake().nextId());
        sysUserRequest.setNickName(sysUserRequest.getRealName());
        sysUserRequest.setBirthday("2020-01-01");
        sysUserRequest.setSex("M");
        sysUserRequest.setEmail(" ");
        sysUserRequest.setPositionId(ProjectConstants.DEFAULT_POSITION_ID);
        if (dto.getRoleId() == 1) {
            // 经理
            sysUserRequest.setGrantRoleIdList(Collections.singletonList(ProjectConstants.ROLE_ID_JL));
        } else {
            // 员工
            sysUserRequest.setGrantRoleIdList(Collections.singletonList(ProjectConstants.ROLE_ID_YG));
        }
        sysUserRequest.setStatusFlag(1);
        sysUserRequest.setOrgId(ProjectConstants.DEFAULT_ORG_ID);//默认添加到总公司下面
        sysUserRequest.setGrantOrgIdList(Collections.singletonList(ProjectConstants.DEFAULT_ORG_ID));
        //sysUserService.add(sysUserRequest);
        addUser(sysUserRequest);

        // 查询个人代理商信息
        AgentVO agentVO = appUserMapper.getAgentInfo(dto.getUserId());

        // 补充代理商信息
        User user = new User();
        user.setUserId(sysUserRequest.getUserId());
        user.setStatusFlag(1);//启用
        user.setAgentId(agentVO.getId());//设置用户代理商信息
        user.setCreateUser(dto.getUserId());
        if (dto.getLeaderId() != null) {
            user.setLeaderId(dto.getLeaderId());
        }
        super.updateById(user);

        // 授权角色
        SysUserRequest request = new SysUserRequest();
        request.setUserId(sysUserRequest.getUserId());
        request.setGrantRoleIdList(sysUserRequest.getGrantRoleIdList());
        //sysUserService.grantRole(request);
        sysUserRoleService.assignRoles(sysUserRequest);

        return true;
    }

    @Override
    public UserVO detail(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        }
        if (dto.getTargetUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "targetUserId不能为空");
        }
        // 查询员工个人信息
        UserVO vo = appUserMapper.getAppUserDetail(dto.getTargetUserId());
        vo.setAvatarUrl(env.getProperty("file-path") + vo.getAvatar());
        vo.setPassword("");
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_AGENT_MANAGER)) {
            vo.setRoleId(0L);
        }
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
            vo.setRoleId(1L);
        }
        if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
            vo.setRoleId(2L);
        }
        return vo;
    }

    @Override
    public boolean edit(UserDTO dto) {
        // 参数校验
        if (dto.getUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        }
        // 【PC&小程序】代理商的账户管理功能，员工状态 在职改离职所有人都可操作，离职改在职只有BMSH管理者权限可操作，其它权限操作时提示（请联系BMSH管理者）
        List<Long> userRole = sysUserRoleService.findRoleIdsByUserId(dto.getUserId());
        User user = userMapper.selectById(dto.getTargetUserId());
        if (dto.getStatusFlag() == 1 && user.getStatusFlag() == 2
                && !userRole.contains(ProjectConstants.ROLE_ID_BMSH_MANAGER)) {
            // 请联系BMSH管理者
            throw new BusinessException(BUSINESS_EXCEPTION, "请联系BMSH管理者！");
        }

        if (dto.getTargetUserId() == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "targetUserId不能为空");
        }

        // 密码参数校验
        if (StringUtils.isNotBlank(dto.getPassword()) && (dto.getPassword().length() < 8 || dto.getPassword().length() > 16)) {
            throw new BusinessException(BUSINESS_EXCEPTION, "密码格式为8-16位数字、字母或符号组合");
        }

        User updateSysUser = new User();
        updateSysUser.setUpdateUser(dto.getUserId());
        updateSysUser.setUserId(dto.getTargetUserId());
        // 修改姓名
        if (StringUtils.isNotBlank(dto.getRealName())) {
            updateSysUser.setRealName(dto.getRealName());
        }
        // 修改手机号
        if (StringUtils.isNotBlank(dto.getPhone())) {
            // 根据手机号查询用户账号
            LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.ne(User::getUserId, dto.getTargetUserId());
            queryWrapper.eq(User::getPhone, dto.getPhone());
            queryWrapper.eq(User::getDelFlag, "N");
            List<User> userList = super.list(queryWrapper);
            if (CollectionUtils.isNotEmpty(userList)) {
                throw new BusinessException(BUSINESS_EXCEPTION, "手机号已经注册！");
            }
            updateSysUser.setPhone(dto.getPhone());
        }
        // 修改账号
        if (StringUtils.isNotBlank(dto.getAccount())) {
            // 根据手机号查询用户账号
            LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.ne(User::getUserId, dto.getTargetUserId());
            queryWrapper.eq(User::getAccount, dto.getAccount());
            queryWrapper.eq(User::getDelFlag, "N");
            List<User> userList = super.list(queryWrapper);
            if (CollectionUtils.isNotEmpty(userList)) {
                throw new BusinessException(BUSINESS_EXCEPTION, "账号已经注册！");
            }
            updateSysUser.setAccount(dto.getAccount());
        }
        // 修改密码
        if (StringUtils.isNotBlank(dto.getPassword())) {
            updateSysUser.setPassword(passwordStoredEncryptApi.encrypt(dto.getPassword()));
        }
        // 修改角色
        if (dto.getRoleId() != null) {
            if (dto.getRoleId() != 1L && dto.getRoleId() != 2L) {
                throw new BusinessException(BUSINESS_EXCEPTION, "roleId不合法");
            }
            if (dto.getRoleId() == 2L && dto.getLeaderId() == null) {
                throw new BusinessException(BUSINESS_EXCEPTION, "员工必须选择直属上级");
            } else {
                updateSysUser.setLeaderId(dto.getLeaderId());
            }
            SysUserRequest sysUserRequest = new SysUserRequest();
            sysUserRequest.setUserId(dto.getTargetUserId());
            if (dto.getRoleId() == 1L) {
                // 经理
                sysUserRequest.setGrantRoleIdList(Collections.singletonList(ProjectConstants.ROLE_ID_JL));
            } else {
                // 员工
                sysUserRequest.setGrantRoleIdList(Collections.singletonList(ProjectConstants.ROLE_ID_YG));
            }
            // 授权角色
            sysUserRoleService.assignRoles(sysUserRequest);
        }
        // 修改状态
        if (dto.getStatusFlag() != 0) {
            if (dto.getStatusFlag() != 1 && dto.getStatusFlag() != 2) {
                throw new BusinessException(BUSINESS_EXCEPTION, "statusFlag不合法");
            }
            updateSysUser.setStatusFlag(dto.getStatusFlag());
        }
        return super.updateById(updateSysUser);
    }

    private void addUser(SysUserRequest sysUserRequest) {
        // 请求bean转为实体，填充一些基本属性
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(sysUserRequest, sysUser, CopyOptions.create().ignoreError());
        SysUserCreateFactory.fillAddSysUser(sysUser);

        // 设置用户默认头像
        sysUser.setAvatar(FileConstants.DEFAULT_AVATAR_FILE_ID);

        // 保存用户
        sysUserService.save(sysUser);

        // 更新用户员工信息
        if (null == sysUserRequest.getPositionId()) {
            sysUserOrgService.add(sysUser.getUserId(), sysUserRequest.getOrgId());
        } else {
            sysUserOrgService.add(sysUser.getUserId(), sysUserRequest.getOrgId(), sysUserRequest.getPositionId());
        }

    }

    private void bindWxMaOpenId(Long userId, String code) {
        try {
            log.info("绑定小程序openId,userId:{},code:{}", userId, code);
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            log.info("sessionInfo:{}", sessionInfo);
            User user = new User();
            user.setUserId(userId);
            user.setWxMaOpenId(sessionInfo.getOpenid());
            user.setWxUnionId(sessionInfo.getUnionid());
            super.updateById(user);
        } catch (Exception e) {
            log.error("绑定小程序openId异常");
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void bindWxMpOpenId(String openId) {
        try {
            WxMpUser wxMpUser = wxMpService.getUserService().userInfo(openId);
            log.info("wxMpUser:{}", wxMpUser);

            if (ObjectUtil.isNotNull(wxMpUser)) {
                List<User> userList = super.list(Wrappers.<User>lambdaQuery().eq(User::getWxUnionId, wxMpUser.getUnionId()));
                //只处理已存在的用户
                if (CollUtil.isNotEmpty(userList)) {
                    userList.forEach(user ->{
                        user.setWxUnionId(wxMpUser.getUnionId());
                        user.setWxMpOpenId(wxMpUser.getOpenId());
                        this.updateById(user);
                    });
                }
            }
        } catch (Exception e) {
            log.error("绑定公众号openId异常");
            log.error(e.getMessage(), e);
        }

    }

    @Override
    public UserVO getWebUserInfo(Long userId) {
        UserVO vo = appUserMapper.findDetail(userId);
        extracted(vo);
        return vo;
    }

    @Override
    public List<UserVO> getAgentUserListByRoleId(UserDTO dto) {
        // 角色赋值
        dto.setUserId(LoginContext.me().getLoginUser().getUserId());
        extracted(dto);
        List<UserVO> userList = appUserMapper.getAgentUserListByAgentId(dto);
        if (CollectionUtils.isNotEmpty(userList)) {
            userList.forEach(vo -> {
                if (vo.getAvatar() != null) {
                    vo.setAvatarUrl(env.getProperty("file-path") + vo.getAvatar());
                }
                if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
                    vo.setRoleId(1L);
                } else if (vo.getRoleId() != null && vo.getRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
                    vo.setRoleId(2L);
                }
            });

            // 只保留经理和员工
            userList.removeIf(vo -> vo.getRoleId() != null
                    && !vo.getRoleId().equals(1L)
                    && !vo.getRoleId().equals(2L));
            if (dto.getCreateUserRoleId() != null && dto.getCreateUserRoleId().equals(ProjectConstants.ROLE_ID_JL)) {
                // 只保留经理
                userList.removeIf(vo -> vo.getRoleId() != null
                        && vo.getRoleId().equals(2L));
            } else if (dto.getCreateUserRoleId() != null && dto.getCreateUserRoleId().equals(ProjectConstants.ROLE_ID_YG)) {
                // 只保留员工
                userList.removeIf(vo -> vo.getRoleId() != null
                        && vo.getRoleId().equals(1L));
            }
        }
        return userList;
    }

    private void extracted(UserVO dto) {
        SysUserRequest sysUserRequest = new SysUserRequest();
        sysUserRequest.setUserId(dto.getUserId());
        SysUserDTO currentUser = sysUserService.detail(sysUserRequest);
        if (CollectionUtils.isEmpty(currentUser.getGrantRoleIdList())) {
            return;
        }
        Long roleId = currentUser.getGrantRoleIdList().get(0);
        if (ProjectConstants.ROLE_ID_BMSH_MANAGER.equals(roleId)) {
            dto.setRoleId(1L);
        } else if (ProjectConstants.ROLE_ID_BMSH_YG.equals(roleId)) {
            dto.setRoleId(2L);
        } else if (ProjectConstants.ROLE_ID_AGENT_MANAGER.equals(roleId)) {
            dto.setRoleId(3L);
        } else if (ProjectConstants.ROLE_ID_JL.equals(roleId)) {
            dto.setRoleId(4L);
        } else if (ProjectConstants.ROLE_ID_YG.equals(roleId)) {
            dto.setRoleId(5L);
        }
    }
}
